Skip to content

feat(validation): add HIL validation for NUCLEO-WB55RG/WBA55CG and fix the driver bugs it found - #95

Merged
gabrielfrasantos merged 19 commits into
mainfrom
ccr-b7e792a2-g2fxib
Oct 5, 2026
Merged

gabrielfrasantos merged 19 commits into
mainfrom
ccr-b7e792a2-g2fxib

Conversation

@gabrielfrasantos

@gabrielfrasantos gabrielfrasantos commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR ports hal-ti's hardware-in-the-loop setup to hal-st for NUCLEO-WB55RG and NUCLEO-WBA55CG. It also fixes the hal-st driver bugs that the new suite found.

Validation app (validation/)

  • Firmware (validation/firmware, target hal_st.validation_firmware):
    • Built when HALST_BUILD_EXAMPLES is on, for stm32wb55 and stm32wba55.
    • Runs an EMIL services/hil terminal on USART1 (ST-LINK VCP, 921600 baud).
    • Exposes the hal-st GPIO/EXTI, PWM, UART (interrupt, DMA, duplex DMA, synchronous, LPUART), SPI, ADC (single, sequence, timer-triggered DMA), QEI (TIM and LPTIM) and WWDG drivers.
    • The command set is specified in validation/PROTOCOL.md.
  • Host (validation/host, Python package hal_st_validation):
    • A pytest suite that drives a Digilent Analog Discovery 3 through ad3-waveforms-bench.
    • Board files (boards/nucleo_wb55rg.yaml, boards/nucleo_wba55cg.yaml) hold the wiring sets and expectations.
    • A fake firmware lets the suite run without hardware.
    • Two depths: quick (pairwise) and full (cartesian).
    • known_gaps marks the driver bugs that are still open.
  • NUCLEO-WB55RG wiring: every pin position (morpho CN7/CN10 and Arduino socket) and every solder bridge is taken from UM2435 Rev 2 (MB1355C), cross-checked with the STM32CubeWB example readmes. TIM2 CH2 / encoder B uses PA1 because PB3 (SWO) is on no header of a stock board. See validation/README.md → "NUCLEO-WB55RG wiring".
  • EMIL is bumped to 0059646 for services/hil.
  • The devcontainer and .vscode launch config can now debug WBA55 through a host ST-LINK GDB server.

Driver fixes

Area Fix
PwmStm Every construction aborted, because Period = 0 failed the HAL IS_TIM_PERIOD assert (all MCUs). Centre-aligned PWM now uses ARR = ticks / 2. Duty is scaled to the alignment's full count. DIR is written only after CMS/SMS are cleared. TRGO, BDTR and BKIN are reset per user. An active-low break input is no longer inverted twice.
ADC (WBA ADC4) Per-channel sampling times map onto the two common groups instead of asserting. Multi-channel sequences now set scan mode and the right sequencer length. New AdcStm::SelectSingleConversion() restores single conversion for the other users. TIM1 drives TRGO2 for the ADC. The trigger table's missing TIM10 slot is added. A repeated channel with a different sampling time is now rejected (all ADCs).
SpiMasterStm, SynchronousSpiMasterStm On SPI v2 (H5/WBA), CSTART is set once per transfer. A receive-only first transfer never started before.
DmaStm On F4/F7, stopping a stream no longer reports the aborted transfer as complete. On GPDMA, SUSPF is cleared after a channel reset.
UartStm & co. SWAP is always written. Destructors clear the interrupt enables, stop TX DMA, call HAL_UART_DeInit and gate the clock; this includes the synchronous UARTs. CR1 updates are atomic. A receive overrun is cleared instead of aborting the firmware or causing an interrupt storm.
GpioStm EXTICR gets the GPIO port index instead of the compacted hal::Port value, which was wrong for port H. The G0 field width is also corrected.
SynchronousQuadratureEncoderLpTimStm The LPTIM is reset before init, so input filters no longer carry over.

Behaviour changes to note

  • A UART receive overrun now drops data instead of aborting the firmware.
  • On WBA ADC4, a multi-channel sequence can use at most 2 distinct sampling times and 8 channels.
  • TimerBaseStm::Trigger gains triggerOutput2, which defaults to reset.
  • G0 is affected too: the EXTICR field width, and the TIM1 TRGO2 reset in PwmStm.

Still open (documented in validation/README.md)

  • SynchronousUartStm: a send blocks with no timeout while CTS is held off. This is the only remaining known_gaps entry (WBA55).
  • uart.send reports completion before the TX FIFO drains.
  • Only the window watchdog is supported.
  • Not addressed here:
    • SynchronousSpiMasterStm can overflow the SPI v2 FIFO on receive-only transfers.
    • SpiSlaveStmDma has SPE handling issues.

Testing

  • Builds: all 13 MCU presets build in RelWithDebInfo with -Werror, including the validation firmware on WB55 (~126 KB flash) and WBA55 (~120 KB flash).
  • Host package: 679 unit tests pass. The fake-firmware run passes on both boards (WB55: 139 passed, 333 skipped; WBA55: 157 passed, 364 skipped). ruff, yamllint and clang-format (on changed lines) pass.
  • Not yet run on hardware. The wiring is in validation/README.md → "Wiring sets".

🤖 Generated with Claude Code

https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno

claude added 13 commits October 3, 2026 20:28
The hardware-in-the-loop validation app builds on EMIL's services.hil and
services.hil.commands, added after the previously pinned commit. The range
only adds those libraries, Terminal command hooks, DutyCycle::FromRatio and
an ISB after disabling an NVIC interrupt; no interface hal-st implements
changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
The destructor always called DisableClockUart(uartIndex), so destroying
LPUART1 switched off USART1's clock instead (and left LPUART1 clocked).
On the Nucleo-WB55/WBA55 USART1 is the ST-LINK virtual COM port.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
…UCLEO-WBA55CG

Mirror hal-ti's validation app: a firmware that exposes the hal-st drivers
through EMIL's services/hil terminal so a host suite and an Analog
Discovery 3 can exercise them on real hardware. The command set is in
validation/PROTOCOL.md.

- target hal_st.validation_firmware, built for stm32wb55 and stm32wba55
  with HALST_BUILD_EXAMPLES (on in every preset)
- terminal on USART1 (ST-LINK VCP) with UartStmDuplexDma at 921600 8N1
- board profiles with alias tables, reserved pins, DMA request lines and
  clocks; STM32 pin factory over the generated pinout tables, guarding
  unbonded pins and shared EXTI lines
- factories for GPIO, UART (UartStm, UartStmDma, UartStmDuplexDma,
  SynchronousUartStm, LPUART), SPI (SpiMasterStm, SpiMasterStmDma,
  SynchronousSpiMasterStm, GPIO chip select), ADC (one-shot and
  timer-triggered AdcDmaMultiChannelStm), PWM (PwmStm, SynchronousPwmStm),
  encoder (timer and LPTIM, plus qei.index) and the WWDG
- comparator, CAN, EEPROM and Ethernet commands answer ERR unsupported
- devcontainer maps host.docker.internal for the bridge setup, and a
  stm32wba55cg debug configuration is added

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
…r review

- SPI: close waits up to 10 ms for an in-flight transfer before destroying
  the driver; SpiMasterStm schedules its completion with no stale-event
  guard, and a WB55 DMA channel left running ignores the next open
- UART: USART1 answers busy only after the argument checks, so argument
  errors keep coming first
- ADC: constant-time trigger timing instead of a prescaler search that
  blocked the event loop; interrupts stay masked through a triggered stop;
  rate without timer is a usage error before range checks
- encoder: lp=1 rejects cap/offset/invb before parsing their values

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
…uite

Port hal-ti's validation host to hal-st: a Python package that drives the
validation firmware terminal and a Digilent Analog Discovery 3 through
ad3-waveforms-bench (pinned to the same commit as hal-ti).

- board files for NUCLEO-WB55RG and NUCLEO-WBA55CG: alias tables, clocks,
  AD3 wiring sets (bundle1, plus bundle2 for the WB55 LPTIM encoder) and
  every test parameter matrix
- typed firmware API, STM32 expectation math (PWM quantisation and range,
  SPI prescaler, UART baud-rate register limits, WWDG period, ADC codes),
  pairwise/full parameter depth, and a fake firmware for --fake runs
- HIL tests for system, GPIO, PWM, UART, SPI, ADC, encoder, watchdog and
  the unsupported groups; unit tests for the harness itself
- known_gaps in the board files: driver bugs found while writing the
  firmware skip (when they abort or hang the board) or xfail the tests
  they affect; --run-known-gaps runs them anyway
- validation/README.md: setup, wiring tables, running, bridge mode and the
  known driver gaps; AGENTS.md and CLAUDE.md point to the new app

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
- ConfigureTimeBase initialised the timer with Period = 0, which fails
  IS_TIM_PERIOD under USE_FULL_ASSERT and aborted every construction. It
  now initialises with Period = 1 and loads the real period in Start.
- The counter direction is written only after CMS and SMS are cleared, as
  CR1.DIR ignores writes while centre-aligned or in encoder mode.
- Centre-aligned: ARR is ticks / 2 (period 2 x ARR) instead of
  ticks / 2 - 1, and duty is scaled to ARR; edge-aligned down-counting
  compensates the extra active tick.
- TRGO (MMS/MMS2), BDTR and the BKIN source are rewritten on every
  construction, so dead time, break, idle and trigger settings of an
  earlier user no longer survive. BKINP stays non-inverted, so an
  active-low break is no longer inverted twice.
- An update event on the first Start loads the preloaded ARR/CCR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
On the WBA ADC4 (CHSELR sequencer, common sampling times):
- AdcDmaMultiChannelStm passed ADC_SAMPLETIME_x where HAL_ADC_ConfigChannel
  takes ADC_SAMPLINGTIME_COMMON_1/2 (assert, abort). Per-channel sampling
  times are now mapped onto the two common groups; a sequence can use at
  most two distinct sampling times, and MaxChannels is 8 on ADC4.
- Scan mode and NbrOfConversion are set for the sequence, and the
  sequencer length is written with the LL encoding instead of the rank
  count.
- AdcStm::SelectSingleConversion restores single-channel scan and SMP1 for
  the single-pin, temperature and timer-triggered DMA users of the same
  AdcStm; the temperature path uses the common sampling time.
- The ADC triggers from TIM1 TRGO2 there, so AdcTimerTriggeredBase now
  configures TRGO2 = update for TIM1 (new TimerBaseStm::Trigger::
  TriggerOutput2).
- The trigger table lacked a TIM10 slot, which shifted the triggers of
  TIM11 and later timers by one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
CSTART was only set when a byte was written to TXDR, so a receive-only
first transfer on H5/WBA never started (SpiMasterStm timed out,
SynchronousSpiMasterStm spun forever). CSTART is now set once per
transfer after the interrupts are enabled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
- Stream-based DMA (F4/F7) sets TCIF once clearing EN takes effect, which
  reported an aborted transfer as complete. StopTransfer now masks TC/HT,
  waits for EN to clear, clears the flags and restores the enables, as
  HAL_DMA_Abort does.
- GPDMA: SUSPF is cleared after the channel reset, so a stale flag no
  longer ends the next suspend wait before the channel is suspended.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
- SWAP is always written, so a swapped instance is no longer swapped for
  later users (UartStm, SynchronousUartStm).
- Destructors clear TXEIE/TCIE/RXNEIE (and RTOEN for the duplex DMA
  variant), and ~UartStmDma stops its transmit DMA, so a close during a
  stalled send no longer leaves an interrupt storm for the next user.
- CR1 enable bits are set and cleared atomically: a TXEIE clear from the
  interrupt during ReceiveData's read-modify-write was undone.
- A receive overrun is cleared instead of asserting (UartStm) or being
  left set (SynchronousUartStm), which looped on the ORE interrupt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
EnableInterrupt wrote the compacted hal::Port value into EXTICR, which
selects the wrong port for ports after a gap (port H on WB/WBA). It now
writes GPIO_GET_INDEX of the port, with the field width taken from the
CMSIS EXTI/SYSCFG EXTICR positions (8 bits on G0, H5 and WBA).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
HAL_LPTIM_Init ORs the clock and trigger filters into CFGR without
clearing them, so a previous user's filter persisted. The LPTIM is now
reset through RCC before it is initialised.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
- Remove the fixed known gaps from both board files; only the
  SynchronousUartStm CTS-held send (WBA55) remains.
- PWM: range check and host expectations follow the fixed ARR
  (ticks - 1 edge, ticks / 2 centre); the centre-period xfail is gone.
- GPIO: port H interrupts are no longer refused.
- README and PROTOCOL list the remaining gaps and the PWM range.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
Copilot AI balanced review requested due to automatic review settings October 4, 2026 10:29
@gabrielfrasantos

gabrielfrasantos commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor Author

✅⚠️MegaLinter analysis: Success with warnings

Descriptor Linter Files Fixed Errors Max errors Warnings Elapsed time
✅ ACTION actionlint 5 0 0 0.15s
✅ CPP clang-format 45 6 0 0 2.17s
✅ CPP cppcheck 45 0 0 1.17s
✅ DOCKERFILE hadolint 1 0 0 0.04s
✅ JSON jsonlint 9 0 0 0.11s
✅ JSON prettier 9 3 0 0 1.53s
⚠️ MARKDOWN markdownlint 18 1 20 0 2.34s
✅ MARKDOWN markdown-table-formatter 18 1 0 0 1.24s
✅ REPOSITORY betterleaks yes no no 1.27s
✅ REPOSITORY checkov yes no no 18.48s
✅ REPOSITORY git_diff yes no no 0.96s
✅ REPOSITORY grype yes no no 101.45s
✅ REPOSITORY ls-lint yes no no 0.01s
⚠️ REPOSITORY osv-scanner yes no 1 0.7s
✅ REPOSITORY secretlint yes no no 1.5s
✅ REPOSITORY syft yes no no 2.37s
✅ REPOSITORY trivy yes no no 13.05s
✅ REPOSITORY trivy-sbom yes no no 0.3s
✅ REPOSITORY trufflehog yes no no 4.68s
⚠️ SPELL lychee 50 6 0 16.44s
✅ YAML prettier 8 1 0 0 1.64s
✅ YAML v8r 8 0 0 5.28s
✅ YAML yamllint 8 0 0 0.55s

Detailed Issues

⚠️ SPELL / lychee - 6 errors
📝 Summary
---------------------
🔍 Total..........282
🔗 Unique.........258
✅ Successful.....271
⏳ Timeouts.........0
🔀 Redirected.....111
👻 Excluded.........5
❓ Unknown..........0
🚫 Errors...........6
⛔ Unsupported......6

Errors in .github/agents/orchestrator.agent.md
[ERROR] file://.github/copilot-instructions.md (at 52:23) | File not found. Check if file exists and path is correct
[ERROR] file://hal_st/cortex/InterruptCortex.hpp (at 56:22) | File not found. Check if file exists and path is correct

Errors in .github/ISSUE_TEMPLATE/add-or-update-hal-driver.md
[ERROR] http://mcd.rou.st.com/modules.php?name=mcu (at 28:63) | Connection failed. Check network connectivity and firewall settings

Errors in README.md
[404] https://api.securityscorecards.dev/projects/github.com/embedded-pro/hal-st (at 3:199) | Rejected status code: 404 Not Found
[ERROR] https://st.com/ (at 5:93) | HTTP/2 protocol error. Server may not support HTTP/2 properly | Followed 1 redirect. Redirects: https://st.com/ --[301]--> https://www.st.com/

Errors in validation/README.md
[403] https://digilent.com/reference/software/waveforms/waveforms-3/start (at 164:12) | Rejected status code: 403 Forbidden

Hint: Followed 111 redirects. You might want to consider replacing redirecting URLs with the resolved URLs. Use verbose mode (`-v`/`-vv`) to see redirection details.
Hint: You can configure accepted/rejected response codes with `-a` or `--accept`
⚠️ MARKDOWN / markdownlint - 20 errors
.github/agents/executor.agent.md:11 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "You are the executor agent for..."]
.github/agents/orchestrator.agent.md:18:401 error MD013/line-length Line length [Expected: 400; Actual: 420]
.github/agents/orchestrator.agent.md:18 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "You are the orchestrator agent..."]
.github/agents/planner.agent.md:11 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "You are the planner agent for ..."]
.github/agents/planner.agent.md:39 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
.github/agents/reviewer.agent.md:14 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "You are the reviewer agent for..."]
.github/agents/reviewer.agent.md:122 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
.github/instructions/hal-st-cpp.instructions.md:18 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
.github/ISSUE_TEMPLATE/add-or-update-hal-driver.md:10 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: "How to import a HAL driver"]
.github/prompts/orchestrate.prompt.md:8 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "Start a new development workfl..."]
CHANGELOG.md:83 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "⚠ BREAKING CHANGES"]
CHANGELOG.md:87 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:94 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Bug Fixes"]
CHANGELOG.md:103 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:122 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Bug Fixes"]
CHANGELOG.md:140 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "⚠ BREAKING CHANGES"]
CHANGELOG.md:144 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:151 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Features"]
CHANGELOG.md:162 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Bug Fixes"]
CLAUDE.md:1 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "hal-st — Claude Instructions"]
⚠️ REPOSITORY / osv-scanner - 1 warning
Scanning dir .
Starting filesystem walk for root: /
End status: 62 dirs visited, 516 inodes visited, 0 Extract calls, 6.388526ms elapsed, 6.388725ms wall time
No package sources found, --help for usage information.


[REPOSITORY_OSV_SCANNER_ERROR_NO_PACKAGE_SOURCES] osv-scanner found no lockfiles, manifests, or SBOMs to scan in the repository.
This is a configuration/scope issue, not a vulnerability finding.
Resolutions:
  - Verify the repository actually contains a supported lockfile (package-lock.json, go.sum, Gemfile.lock, Pipfile.lock, etc.) at the scanned path.
  - If this is expected for some sub-projects, disable osv-scanner for the affected paths or mark it non-blocking via `DISABLE_ERRORS_LINTERS`.

Notices

⚠️ Your configuration references items that have been removed from MegaLinter and are ignored: REPOSITORY_GITLEAKS, REPOSITORY_KICS. See Removed linters to find their replacements.

See detailed reports in MegaLinter artifacts

Your project could benefit from a custom flavor, which would allow you to run only the linters you need, and thus improve runtime performances. (Skip this info by defining FLAVOR_SUGGESTIONS: false)

  • Documentation: Custom Flavors
  • Command: npx mega-linter-runner@10.1.0 --custom-flavor-setup --custom-flavor-linters ACTION_ACTIONLINT,CPP_CPPCHECK,CPP_CLANG_FORMAT,DOCKERFILE_HADOLINT,JSON_JSONLINT,JSON_PRETTIER,MARKDOWN_MARKDOWNLINT,MARKDOWN_MARKDOWN_TABLE_FORMATTER,REPOSITORY_CHECKOV,REPOSITORY_GIT_DIFF,REPOSITORY_BETTERLEAKS,REPOSITORY_GRYPE,REPOSITORY_LS_LINT,REPOSITORY_OSV_SCANNER,REPOSITORY_SECRETLINT,REPOSITORY_SYFT,REPOSITORY_TRIVY,REPOSITORY_TRIVY_SBOM,REPOSITORY_TRUFFLEHOG,SPELL_LYCHEE,YAML_PRETTIER,YAML_YAMLLINT,YAML_V8R

MegaLinter is provided by OX Security
Show us your support by starring ⭐ the repository

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

UART destructors omit required deinitialization/clock cleanup, and ADC4 can silently misapply sampling times for repeated channels.

Review effort: Balanced
Findings: 3 Medium severity

Open (3)
What changed in this PR

Adds WB55/WBA55 hardware-in-the-loop validation infrastructure and fixes driver defects exposed by it.

Changes:

  • Adds validation firmware, host tooling, board profiles, and HIL tests.
  • Fixes PWM, ADC, UART, SPI, DMA, GPIO, timer, and QEI behavior.
  • Updates build, debugging, and contributor documentation.
File Description
validation/​host/​tests/​unit/​test_terminal_alignment.py Tests delayed terminal replies.
validation/​host/​tests/​unit/​test_protocol.py Tests pins, aliases, and responses.
validation/​host/​tests/​unit/​test_pairwise.py Tests matrix generation.
validation/​host/​tests/​unit/​test_known_gaps.py Tests known-gap handling.
validation/​host/​tests/​unit/​test_firmware.py Tests host command formatting.
validation/​host/​tests/​hil/​test_watchdog.py Validates watchdog behavior.
validation/​host/​tests/​hil/​test_unsupported.py Validates unsupported commands.
validation/​host/​tests/​hil/​test_system.py Validates system protocol behavior.
validation/​host/​tests/​hil/​test_spi.py Validates SPI drivers.
validation/​host/​tests/​hil/​test_qei.py Validates timer/LPTIM QEI.
validation/​host/​tests/​hil/​test_gpio.py Validates GPIO and EXTI.
validation/​host/​tests/​hil/​test_adc.py Validates ADC sequences and triggers.
validation/​host/​pyproject.toml Defines host package and tooling.
validation/​host/​hal_st_validation/​protocol.py Implements pin protocol helpers.
validation/​host/​hal_st_validation/​pairwise.py Implements test-matrix generation.
validation/​host/​hal_st_validation/​console.py Adds validation console entry point.
validation/​host/​hal_st_validation/​__init__.py Exports host APIs.
validation/​host/​.gitignore Ignores Python artifacts.
validation/​firmware/​WatchDogFactory.hpp Declares watchdog factory.
validation/​firmware/​WatchDogFactory.cpp Implements watchdog validation adapter.
validation/​firmware/​UnsupportedGroups.hpp Declares unsupported groups.
validation/​firmware/​UnsupportedGroups.cpp Registers unsupported commands.
validation/​firmware/​UartFactory.hpp Declares UART factory.
validation/​firmware/​TimerAllocation.hpp Declares timer ownership tracking.
validation/​firmware/​TimerAllocation.cpp Implements timer ownership.
validation/​firmware/​SpiFactory.hpp Declares SPI factory.
validation/​firmware/​SpiFactory.cpp Implements SPI validation adapters.
validation/​firmware/​QeiFactory.hpp Declares QEI factory.
validation/​firmware/​QeiFactory.cpp Implements QEI validation adapters.
validation/​firmware/​PwmFactory.hpp Declares PWM factory.
validation/​firmware/​PinFactoryStm.hpp Declares managed validation pins.
validation/​firmware/​PinFactoryStm.cpp Implements pin ownership and capabilities.
validation/​firmware/​PeripheralClocks.hpp Declares timer clock helpers.
validation/​firmware/​PeripheralClocks.cpp Resolves timer clocks.
validation/​firmware/​Main.cpp Composes validation firmware.
validation/​firmware/​Console.hpp Declares terminal infrastructure.
validation/​firmware/​Console.cpp Configures validation UART.
validation/​firmware/​CMakeLists.txt Builds validation firmware.
validation/​firmware/​BoardTypes.hpp Defines shared board types.
validation/​firmware/​boards/​stm32wba55/​BoardProfile.hpp Defines WBA55 board mapping.
validation/​firmware/​boards/​stm32wb55/​BoardProfile.hpp Defines WB55 board mapping.
validation/​firmware/​BoardInfoStm.hpp Declares board information provider.
validation/​firmware/​BoardInfoStm.cpp Reports board and reset information.
validation/​firmware/​AdcFactory.hpp Declares ADC factory.
validation/​firmware/​AdcFactory.cpp Implements ADC validation sequences.
validation/​CMakeLists.txt Includes validation firmware.
hal_st/​synchronous_stm32fxxx/​SynchronousUartStm.cpp Updates UART cleanup and overrun handling.
hal_st/​synchronous_stm32fxxx/​SynchronousSpiMasterStm.cpp Starts SPI v2 transfers correctly.
hal_st/​synchronous_stm32fxxx/​SynchronousQuadratureEncoderLpTimStm.cpp Resets LPTIM before initialization.
hal_st/​stm32fxxx/​UartStmDuplexDma.cpp Clears receiver-timeout state.
hal_st/​stm32fxxx/​UartStmDma.cpp Stops transmit DMA during destruction.
hal_st/​stm32fxxx/​UartStm.cpp Updates UART initialization and interrupts.
hal_st/​stm32fxxx/​TimerStm.hpp Adds TRGO2 configuration.
hal_st/​stm32fxxx/​TimerStm.cpp Applies TRGO2 configuration.
hal_st/​stm32fxxx/​SpiMasterStm.cpp Starts SPI v2 transfers once.
hal_st/​stm32fxxx/​PwmStm.hpp Documents down-counting limitation.
hal_st/​stm32fxxx/​PwmStm.cpp Corrects PWM initialization and scaling.
hal_st/​stm32fxxx/​GpioStm.cpp Corrects EXTI port encoding.
hal_st/​stm32fxxx/​DmaStm.cpp Corrects DMA cancellation/reset handling.
hal_st/​stm32fxxx/​AnalogToDigitalPinStm.hpp Exposes single-conversion selection.
hal_st/​stm32fxxx/​AnalogToDigitalPinStm.cpp Restores single-channel ADC state.
hal_st/​stm32fxxx/​AdcTimerTriggeredBase.cpp Adds TIM10 and TRGO2 support.
hal_st/​stm32fxxx/​AdcDmaStm.cpp Restores single-conversion mode.
hal_st/​stm32fxxx/​AdcDmaMultiChannelStm.hpp Limits ADC4 sequences to eight ranks.
hal_st/​stm32fxxx/​AdcDmaMultiChannelStm.cpp Configures ADC sequences and sampling groups.
CMakeLists.txt Updates EMIL and includes validation.
CLAUDE.md Documents validation workflow.
AGENTS.md Documents validation architecture and commands.
.vscode/​launch.json Adds WBA55 debugging.
.devcontainer/​devcontainer.json Exposes the host debugger.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread hal_st/stm32fxxx/AdcDmaMultiChannelStm.cpp
Comment thread hal_st/stm32fxxx/UartStm.cpp
Comment thread hal_st/synchronous_stm32fxxx/SynchronousUartStm.cpp
claude and others added 6 commits October 4, 2026 11:10
…der positions

PB3 (TIM2 CH2, SWO) is on no header of a stock NUCLEO-WB55RG: CN10-30
carries PB13 unless SB12/SB13 are reworked (UM2435 Rev 2, Fig. 8,
Table 11). TIM2 CH2 and the default encoder B move to PA1 (A2, CN7-32
via SB14), the only other TIM2 CH2 pin.

Every WB55 wiring row now names its morpho pin and Arduino socket from
UM2435 Rev 2 (MB1355C), plus the ground pins, the solder bridges on the
path, the D10 bridge note (PA4 by default, confirmed) and the terminal
pins to keep free. The loopback note says what the SPI tests do with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
AGENTS.md asks for HAL_FOO_DeInit and a clock disable in every driver
destructor. UartStm gated the clock without HAL_UART_DeInit, and
SynchronousUartStm/SynchronousUartStmSendOnly did neither. The explicit
interrupt-enable clear stays: the F4 HAL_UART_DeInit leaves CR1 as is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
The sampling time (SMPRx, or SMPSEL on ADC4) belongs to the channel, not
to the rank, so configuring a repeated channel with another sampling time
silently changed the earlier rank too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
Formatted with markdown-table-formatter, as MegaLinter suggests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
@gabrielfrasantos
gabrielfrasantos merged commit 029a910 into main Oct 5, 2026
15 checks passed
@gabrielfrasantos
gabrielfrasantos deleted the ccr-b7e792a2-g2fxib branch October 5, 2026 13:30
gabrielfrasantos pushed a commit that referenced this pull request Oct 5, 2026
main's #95 squash commit has the same tree as the #95 head this branch
is built on, so every add/add conflict resolves to this branch's version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQVqtLNig9iboP9KR4Snno
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants